package com.ruoyi.demo.websocket;

import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Slf4j
// 接口路径 ws://localhost:8080/webSocket/token;
@ServerEndpoint("/websocket/{token}")
public class WebSocket {

    /**
     * 用来存在线连接用户信息
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     * 虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
     */
    private static ConcurrentHashMap<Long, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * 登录用户
     */
    private static ConcurrentHashMap<Long, LoginUser> loginUserMap = new ConcurrentHashMap<>();


    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "token") String token) {
        try {
            LoginUser loginUser = LoginHelper.getLoginUser(token);
            if (Objects.isNull(loginUser)) {
                log.error("Token 失效或无法解析！！！");
                session.close();
                return;
            }
            Long userId = loginUser.getUserId();
            sessionMap.put(userId, session);
            loginUserMap.put(userId, loginUser);
            log.info("用户：{}，{} 登录 ，当前在线人数为：{} 人", userId, loginUser.getUsername(), sessionMap.size());
            sendOneMessage(userId,
                "你好" + userId + "我是来自服务器的消息！！！"
                    + userId + "登录了系统" + "当前在线人数为" + sessionMap.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        try {
            Long userId = getUserIdBySession(session);
            if (userId == null) return;
            LoginUser loginUser = loginUserMap.get(userId);
            // 先发消息，再移除
            sendOneMessage(userId,
                "=====>>> 你好" + loginUser.getUsername() + "我是来自服务器的消息！！！"
                    + userId + "退出登录了" + "当前在线人数为" + sessionMap.size());
            sessionMap.remove(userId);
            loginUserMap.remove(userId);
            log.info("用户：{} {}退出登录 ，当前在线人数为：{} 人", userId, loginUser.getUsername(), sessionMap.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Long getUserIdBySession(Session session) {
        Long userId = null;
        for (Long id : sessionMap.keySet()) {
            if (sessionMap.get(id).getId().equals(session.getId())) {
                userId = id;
            }
        }
        return userId;
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        Long userId = getUserIdBySession(session);
        if (Objects.isNull(userId)) {
            return;
        }
        LoginUser loginUser = loginUserMap.get(userId);
        if (Objects.isNull(loginUser)) {
            return;
        }
        if (UserType.SYS_USER.equals(loginUser.getUserType())) {
            log.info("PC端客户");
        } else if (UserType.APP_USER.equals(loginUser.getUserType())) {
            log.info("APP端客户");
        }
        log.info("收到客户端消息：{} {} 的信息 {}", userId, loginUser.getUsername(), message);
    }

    /**
     * 发送错误时的处理
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误，原因：" + error.getMessage());
        error.printStackTrace();
    }


    // 此为广播消息
//    public void sendAllMessage(String message) {
//        log.info("【websocket消息】广播消息:" + message);
//        for (WebSocket webSocket : webSockets) {
//            try {
//                if (webSocket.session.isOpen()) {
//                    webSocket.session.getAsyncRemote().sendText(message);
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }

    // 此为单点消息
    public void sendOneMessage(Long userId, String message) {
        Session session = sessionMap.get(userId);
        if (Objects.isNull(userId) || StringUtils.isBlank(message)) {
            log.info("消息不完整！！！");

        }

        if (sessionMap.containsKey(userId)) {
            try {
                log.info("发送给 {} 客户端的消息为 ======>>> {}", userId, message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            log.info("用户 {} 不在线！！！", userId);
        }

    }

    // 此为单点消息(多人)
//    public void sendMoreMessage(String[] tokens, String message) {
//        for (String token : tokens) {
//            Session session = sessionMap.get(token);
//            if (session != null && session.isOpen()) {
//                try {
//                    log.info("【websocket消息】 单点消息:" + message);
//                    session.getAsyncRemote().sendText(message);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//
//    }

}
